package com.xlh.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.jcraft.jsch.ChannelSftp;
import com.xlh.common.Result;
import com.xlh.common.ResultEnum;
import com.xlh.dto.QuestionTransportDTO;
import com.xlh.dto.course.*;
import com.xlh.dto.system.ResourceRelationDTO;
import com.xlh.enums.*;
import com.xlh.enums.course.ChapterEnum;
import com.xlh.enums.course.CourseStatusEnum;
import com.xlh.enums.course.TemplateTypeEnum;
import com.xlh.exception.common.GlobalException;
import com.xlh.exception.common.NotFoundException;
import com.xlh.pojo.course.*;
import com.xlh.pojo.system.Resource;
import com.xlh.pojo.system.ResourceRelation;
import com.xlh.pojo.system.SystemConfig;
import com.xlh.service.ConvertToolService;
import com.xlh.service.course.*;
import com.xlh.service.courseTest.QuestionTransportService;
import com.xlh.service.system.SystemConfigService;
import com.xlh.service.system.SystemResourceService;
import com.xlh.support.training.dao.TrainingMapper;
import com.xlh.support.training.domain.Training;
import com.xlh.support.training.domain.example.TrainingExample;
import com.xlh.util.BeanUtil;
import com.xlh.util.CmdUtil;
import com.xlh.util.JDBCTemplateUtil;
import com.xlh.util.SshUtil;
import com.xlh.virtualization.constant.ContextTypeEnum;
import com.xlh.virtualization.service.ExperimentJudgeService;
import com.xlh.virtualization.service.ImageAllocationService;
import com.xlh.websocket.CourseImportWebsocket;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 课程数据转换工具
 * <p>
 * Created by lx on 2019/11/26.
 */
@Service
public class ConvertToolServiceImpl implements ConvertToolService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConvertToolServiceImpl.class);

    @Autowired
    private ChapterService chapterService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private SystemResourceService resourceService;

    @Autowired
    private TechnologyService technologyService;

    @Autowired
    private SystemConfigService configService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    private DirectionService directionService;

    @Autowired
    private QuestionTransportService questionTransportService;

    @Autowired
    private ImageAllocationService imageAllocationService;

    @Autowired
    private TrainingMapper trainingMapper;

    @Autowired
    private ExperimentJudgeService experimentJudgeService;

    @Autowired
    private StepService stepService;

    @Value("${resources.root-dir}")
    private String path;

    private String remoteChapterSQL = "SELECT " +
            "c.id, " +
            "cb.`name`, " +
            "cb.type, " +
            "cb.introduction, " +
            "cb.technology_ids, " +
            "c.course_id, " +
            "c.chapter_basic_id, " +
            "c.order_number, " +
            "c.parent_id, " +
            "c.difficulty_score, " +
            "cb.step_type " +
            "FROM " +
            "chapter c, " +
            "chapter_basic cb " +
            "WHERE " +
            "c.chapter_basic_id = cb.id " +
            "AND c.is_deleted = FALSE " +
            "AND cb.is_deleted = FALSE " +
            "{}" +
            "ORDER BY c.course_id DESC, c.parent_id ASC, c.order_number ASC";

    private String remoteChapterConditionSQL = "AND (c.id IN ({}) OR c.parent_id IN ({}))";

    private String remoteChapterConditionSQL2 = "AND c.course_id IN ({})";

    private String remoteCourseSQL = "SELECT " +
            "c.id, " +
            "cb.`name`, " +
            "cb.`type`, " +
            "cb.icon, " +
            "cb.introduction, " +
            "cb.`status`, " +
            "cb.resource_id, " +
            "cb.is_preseted, " +
            "c.is_own_course, " +
            "c.user_id, " +
            "cb.id AS course_basic_id, " +
            "cb.image_load_type " +
            "FROM " +
            "course c, " +
            "course_basic cb " +
            "WHERE " +
            "c.course_basic_id = cb.id " +
            "AND c.is_deleted = FALSE " +
            "AND cb.is_deleted = FALSE " +
            "AND c.is_own_course = TRUE " +
            "AND cb.is_preseted = TRUE " +
            "AND cb. STATUS = " + CourseStatusEnum.SHARED.getCode() + " " +
            "{}" +
            "ORDER BY " +
            "c.id DESC";

    private String remoteCourseConditionSQL = "AND c.id IN ({})";

    private String remoteResourceSQL = "SELECT " +
            "id, " +
            "`type`, " +
            "`name`, " +
            "file_name, " +
            "remark " +
            "FROM " +
            "resource " +
            "WHERE " +
            "id IN ({})";

    private String remoteResourceRelationSQL = "SELECT " +
            "id, " +
            "obj_id, " +
            "resource_id, " +
            "`type` " +
            "FROM " +
            "resource_relation {}";

    private String remoteResourceRelationConditionSQL = "WHERE " +
            "obj_id IN ({}) " +
            "AND `type` = {} ";

    private String remoteTechnologySQL = "SELECT " +
            "id, " +
            "`name`, " +
            "introduction " +
            "FROM " +
            "technology " +
            "WHERE " +
            "id IN ({})";

    private String remoteChapterBasicSQL = "SELECT " +
            "id, " +
            "`name`, " +
            "`type`, " +
            "introduction, " +
            "technology_ids, " +
            "is_deleted, " +
            "step_type " +
            "FROM " +
            "chapter_basic " +
            "WHERE " +
            "id IN ({})";

    private String remoteChapterInfoSQL = "SELECT " +
            "id, " +
            "course_id, " +
            "chapter_basic_id, " +
            "order_number, " +
            "is_deleted, " +
            "parent_id, " +
            "difficulty_score " +
            "FROM " +
            "chapter " +
            "WHERE " +
            "id IN ({})";

    private String remoteCourseSortSQL = "SELECT " +
            "id, " +
            "course_id, " +
            "`name`, " +
            "order_num " +
            "FROM " +
            "course_sort " +
            "WHERE " +
            "course_id IN ({})";

    private String remoteChapterCourseSortSQL = "SELECT " +
            "id, " +
            "course_sort_id, " +
            "chapter_id " +
            "FROM " +
            "chapter_course_sort " +
            "WHERE " +
            "course_sort_id IN ({})";

    private String remoteIconSQL = "SELECT " +
            "id, " +
            "key_word, " +
            "key_value, " +
            "remark " +
            "FROM " +
            "system_config " +
            "WHERE " +
            "key_word IN ({})";

    private String remoteCourseResourceSQL = "SELECT " +
            "rr.obj_id, " +
            "rr.id AS resource_relation_id, " +
            "r.id AS resource_id, " +
            "r.`name`, " +
            "r.file_name, " +
            "r.remark, " +
            "r.`type` " +
            "FROM " +
            "resource_relation rr, " +
            "resource r " +
            "WHERE " +
            "rr.resource_id = r.id " +
            "AND rr.obj_id IN ({}) " +
            "AND r.`type` IN ({}) " +
            "AND rr.`type` = {}";

    private String remoteDirectionSQL = "SELECT " +
            "id, " +
            "`type`, " +
            "`name`, " +
            "order_num " +
            "FROM " +
            "direction " +
            "ORDER BY `type` , order_num";

    private String remoteCourseExtendSQL = "SELECT " +
            "id, " +
            "course_id, " +
            "direction_id " +
            "FROM " +
            "course_extend " +
            "WHERE " +
            "course_id IN ({})";

    private String remoteStepSQL = "SELECT " +
            "id, " +
            "`name` " +
            "FROM " +
            "step " +
            "WHERE " +
            "id IN ({})";

    private String remoteStepChapterSQL = "SELECT " +
            "id, " +
            "step_id, " +
            "chapter_id, " +
            "order_number " +
            "FROM " +
            "step_chapter " +
            "WHERE " +
            "chapter_id IN ({}) " +
            "order by order_number ASC";

    private String remoteCourseFile = "/course/{}/{}";

    private String remoteChapterFile = "/course/{}/chapter-resources/{}";

    @Override
    public List<ZtreeDTO> queryRemoteCourseChapterZtree(
            String remoteDBIp, String remoteDBPort, String remoteDBName, String remoteDBUser, String remoteDBPassword) {

        JdbcTemplate jdbcTemplate = JDBCTemplateUtil.getJdbcTemplate(
                remoteDBIp, remoteDBPort, remoteDBName, remoteDBUser, remoteDBPassword);

        // 获取远程服务器课程信息
        List<CourseBasicDTO> courses = queryRemoteCourses(jdbcTemplate, "");
        if (CollectionUtils.isEmpty(courses)) throw new NotFoundException("");

        // 获取远程章节信息
        List<ChapterBasicInfoDTO> chapters = queryRemoteChapters(jdbcTemplate,
                "AND c.course_id IN (" + courses.stream()
                        .map(courseBasicDTO -> String.valueOf(courseBasicDTO.getId()))
                        .collect(Collectors.joining(",")) + ") ");

        // 将远程服务器数据 与 现在服务器数据进行比较
        return convertZtree(courses, chapters);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importCourse(
            String remoteDBIp, String remoteDBPort, String remoteDBName, String remoteDBUser, String remoteDBPassword,
            String remoteIp, String remoteUser, String remotePwd, Integer remotePort,
            String remoteResourcesPath, List<Long> chapterIds, Long userId) {

        JdbcTemplate jdbcTemplate = JDBCTemplateUtil.getJdbcTemplate(
                remoteDBIp, remoteDBPort, remoteDBName, remoteDBUser, remoteDBPassword);

        // 检查参数 并 获取远程服务器已选中的章节及任务信息
        List<ChapterBasicInfoDTO> selectedChaptersAndTask = checkAndGetRemoteChapterTask(chapterIds, jdbcTemplate);

        // 获取已选中的远程服务器课程信息
        List<CourseBasicDTO> remoteCourses = checkAndGetRemoteCourse(selectedChaptersAndTask.stream()
                .map(ChapterBasicInfoDTO::getCourseId).distinct().collect(Collectors.toList()), jdbcTemplate);

        // 获取远程服务器课程下的所有章节（用这个来判断 是更新整门课程 还是 更新章节）
        List<ChapterBasicInfoDTO> remoteChapters = queryRemoteChapters(jdbcTemplate,
                MessageFormatter.format(remoteChapterConditionSQL2, remoteCourses.stream()
                        .map(courseBasicDTO -> String.valueOf(courseBasicDTO.getId()))
                        .collect(Collectors.joining(","))).getMessage());

        // 获取目前数据库的课程
        List<CourseBasicDTO> courses = courseService.listCourse(
                null, true, true, CourseStatusEnum.SHARED.getCode());

        // 获取目前数据库的章节
        List<ChapterBasicInfoDTO> chapters = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(courses)) {
            chapters = chapterService.listChapterInfo(
                    courses.stream().map(CourseBasicDTO::getId).collect(Collectors.toList()), null, null);
        }

        String info = "导入课程整体进度%s/" + remoteCourses.size();

        // 导入system_config表中课程等图标
        List<String> icons = Lists.newArrayList(
                SystemConfigEnum.COURSE_ICON.getKey(), SystemConfigEnum.IMAGE_ICON.getKey());
        List<SystemConfig> remoteSystemConfigs = queryRemoteSystemConfig(
                jdbcTemplate, icons.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")));
        List<SystemConfig> configs = configService.listConfigByKeys(icons);
        Map<Integer, Integer> iconMap = importIcon(remoteSystemConfigs, configs);
        sendMessageAndRecordLogger(
                String.format("数据库图标导入完毕... %s", String.format(info, 0)), userId);

        // 导入方向
        Map<Long, Long> directionMap = importDirection(jdbcTemplate);
        sendMessageAndRecordLogger(
                String.format("数据库方向导入完毕... %s", String.format(info, 0)), userId);

        // 导入课程
        List<String> deleteResources = Lists.newArrayList();
        Map<String, List<String>> resourcePathMap = Maps.newHashMap();
        for (int i = 0; i < remoteCourses.size(); i++) {
            CourseBasicDTO remoteCourse = remoteCourses.get(i);
            String importInfo = String.format(info, i + 1);

            // 获取当前服务器的课程信息
            List<CourseBasicDTO> courseList = courses.stream()
                    .filter(courseBasicDTO -> Objects.equals(courseBasicDTO.getName(), remoteCourse.getName()))
                    .collect(Collectors.toList());

            // 导入/更新课程基本信息
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入课程基本信息... %s", remoteCourse.getName(), importInfo), userId);
            Map<Long, Long> courseIdMap = importRemoteCourse(
                    remoteCourse, CollectionUtils.isEmpty(courseList) ? null : courseList.get(0), iconMap, userId);
            Long newCourseId = courseIdMap.get(remoteCourse.getId());

            // 获取远程服务器课程下选中的章节
            List<ChapterBasicInfoDTO> remoteSelectedCourseChapters = selectedChaptersAndTask.stream()
                    .filter(chapterBasicInfoDTO ->
                            Objects.equals(chapterBasicInfoDTO.getCourseId(), remoteCourse.getId()))
                    .collect(Collectors.toList());

            // 是否选中课程
            boolean selectedCourse = isSelectedCourse(
                    remoteChapters, remoteCourse.getId(), remoteSelectedCourseChapters);

            // 导入技术库、章节 并获取删除的静态资源信息 以及 章节对应map结果集
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入章节基本信息... %s", remoteCourse.getName(), importInfo), userId);
            Map<DatabaseOperationEnum, Object> chapterMap = importRemoteChapter(
                    newCourseId, remoteSelectedCourseChapters, chapters, selectedCourse, jdbcTemplate);
            List<String> deleteData = MapUtils.isNotEmpty(chapterMap)
                    && chapterMap.get(DatabaseOperationEnum.DELETE) != null ?
                    (List<String>) chapterMap.get(DatabaseOperationEnum.DELETE) : null;
            Map<Long, Long> insertChapterMap = MapUtils.isNotEmpty(chapterMap)
                    && chapterMap.get(DatabaseOperationEnum.INSERT) != null
                    && MapUtils.isNotEmpty((Map<Long, Long>) chapterMap.get(DatabaseOperationEnum.INSERT)) ?
                    (Map<Long, Long>) chapterMap.get(DatabaseOperationEnum.INSERT) : null;
            if (CollectionUtils.isNotEmpty(deleteData)) {
                deleteResources.addAll(deleteData);
            }

            // 导入步骤信息
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入步骤基本信息... %s", remoteCourse.getName(), importInfo), userId);
            Map<DatabaseOperationEnum, Object> stepMap = importStep(insertChapterMap, jdbcTemplate);
            List<String> stepDeleteData = MapUtils.isNotEmpty(stepMap)
                    && stepMap.containsKey(DatabaseOperationEnum.DELETE) ?
                    (List<String>) stepMap.get(DatabaseOperationEnum.DELETE) : null;
            Map<Long, Long> insertStepMap = MapUtils.isNotEmpty(stepMap)
                    && stepMap.containsKey(DatabaseOperationEnum.INSERT)
                    && MapUtils.isNotEmpty((Map<Long, Long>) stepMap.get(DatabaseOperationEnum.INSERT)) ?
                    (Map<Long, Long>) stepMap.get(DatabaseOperationEnum.INSERT) : null;
            if (CollectionUtils.isNotEmpty(stepDeleteData)) {
                deleteResources.addAll(stepDeleteData);
            }

            // 导入课程与专业方向的关联关系
            if (selectedCourse || CollectionUtils.isEmpty(courseList)) {
                sendMessageAndRecordLogger(
                        String.format("【%s】正在导入课程专业方向... %s", remoteCourse.getName(), importInfo), userId);
                importCourseExtend(directionMap, courseIdMap, jdbcTemplate);

            }

            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入其他信息... %s", remoteCourse.getName(), importInfo), userId);

            // 导入课程关联信息
            if (selectedCourse) {

                // 课程预置资源
                sendMessageAndRecordLogger(
                        String.format("【%s】正在导入预置资源... %s", remoteCourse.getName(), importInfo), userId);
                Map<DatabaseOperationEnum, Object> presetMap = importCourseResource(
                        newCourseId, remoteCourse.getResourceId(),
                        CollectionUtils.isEmpty(courseList) ? null : courseList.get(0).getResourceId(), jdbcTemplate);
                String presetDeleteData = MapUtils.isNotEmpty(presetMap)
                        && presetMap.get(DatabaseOperationEnum.DELETE) != null ?
                        (String) presetMap.get(DatabaseOperationEnum.DELETE) : null;
                Map<String, String> importResourceMap = MapUtils.isNotEmpty(presetMap)
                        && presetMap.get(DatabaseOperationEnum.UPDATE) != null ?
                        (Map<String, String>) presetMap.get(DatabaseOperationEnum.UPDATE) : null;
                if (StringUtils.isNotBlank(presetDeleteData)) {
                    deleteResources.add(presetDeleteData);
                }
                if (MapUtils.isNotEmpty(importResourceMap)) {
                    convertResource(resourcePathMap, importResourceMap);
                }

                // 导入课程资源
                sendMessageAndRecordLogger(
                        String.format("【%s】正在导入课程资源... %s", remoteCourse.getName(), importInfo), userId);
                Map<DatabaseOperationEnum, Object> courseResouceMap = importCourseResouce(courseIdMap, jdbcTemplate);
                List<String> deleteCourseResources = MapUtils.isNotEmpty(courseResouceMap)
                        && courseResouceMap.get(DatabaseOperationEnum.DELETE) != null ?
                        (List<String>) courseResouceMap.get(DatabaseOperationEnum.DELETE) : null;
                Map<String, String> insertCourseResourceMap = MapUtils.isNotEmpty(courseResouceMap)
                        && courseResouceMap.get(DatabaseOperationEnum.INSERT) != null
                        && MapUtils.isNotEmpty(
                        (Map<String, String>) courseResouceMap.get(DatabaseOperationEnum.INSERT)) ?
                        (Map<String, String>) courseResouceMap.get(DatabaseOperationEnum.INSERT) : null;
                if (CollectionUtils.isNotEmpty(deleteCourseResources)) {
                    deleteResources.addAll(deleteCourseResources);
                }
                if (MapUtils.isNotEmpty(insertCourseResourceMap)) {
                    convertResource(resourcePathMap, insertCourseResourceMap);
                }

                // 导入章节分类
                if (MapUtils.isNotEmpty(insertChapterMap)) {
                    sendMessageAndRecordLogger(
                            String.format("【%s】正在导入章节分类... %s", remoteCourse.getName(), importInfo), userId);
                    importCourseSort(courseIdMap, insertChapterMap, jdbcTemplate);

                }

                sendMessageAndRecordLogger(
                        String.format("【%s】正在导入其他信息... %s", remoteCourse.getName(), importInfo), userId);

            }

            // 若选中是课程 需要修改课程基本信息
            if (selectedCourse && CollectionUtils.isNotEmpty(courseList)) {
                CourseBasic courseBasic = new CourseBasic();
                courseBasic.setId(courseList.get(0).getCourseBasicId());
                courseBasic.setName(remoteCourse.getName());
                courseBasic.setType(remoteCourse.getType());
                courseBasic.setIcon(iconMap.get(remoteCourse.getIcon()));
                courseBasic.setIntroduction(remoteCourse.getIntroduction());
                courseBasic.setImageLoadType(remoteCourse.getImageLoadType());
                courseService.updateCourse(courseBasic);
                LOGGER.info(String.format("【%s】课程信息模块2导入完毕... %s", remoteCourse.getName(), importInfo));
            }

            if (MapUtils.isEmpty(insertChapterMap)) continue;

            // 导入题库
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入题库... %s", remoteCourse.getName(), importInfo), userId);
            QuestionTransportDTO transport = questionTransportService.transport(jdbcTemplate, userId, courseIdMap, insertChapterMap, selectedCourse);

            // 导入镜像
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入镜像... %s", remoteCourse.getName(), importInfo), userId);
            imageAllocationService.transport(ContextTypeEnum.TASK.getCode(), jdbcTemplate, courseIdMap, insertChapterMap, iconMap);

            // 导入考试镜像
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入考试镜像... %s", remoteCourse.getName(), importInfo), userId);
            imageAllocationService.transport(ContextTypeEnum.QUESTION.getCode(), jdbcTemplate, courseIdMap, transport.getExprimentIdsMap(), iconMap);

            // 导入实验判定
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入实验判定... %s", remoteCourse.getName(), importInfo), userId);
            if (MapUtils.isEmpty(insertStepMap)) {
                insertStepMap = Maps.newHashMap();
            }
            experimentJudgeService.transport(jdbcTemplate, insertChapterMap, insertStepMap);

            // 导入资源
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入章节资源... %s", remoteCourse.getName(), importInfo), userId);
            Map<String, String> resourceMap = importResource(
                    newCourseId, insertChapterMap, ResourceRelationTypeEnum.CHAPTER, deleteResources, jdbcTemplate);
            if (MapUtils.isNotEmpty(resourceMap)) {
                convertResource(resourcePathMap, resourceMap);
            }
            sendMessageAndRecordLogger(
                    String.format("【%s】正在导入步骤资源... %s", remoteCourse.getName(), importInfo), userId);
            Map<String, String> stepResourceMap = importResource(
                    newCourseId, insertStepMap, ResourceRelationTypeEnum.STEP, deleteResources, jdbcTemplate);
            if (MapUtils.isNotEmpty(stepResourceMap)) {
                convertResource(resourcePathMap, stepResourceMap);
            }

        }

        // 导静态资源
        importStaticResource(deleteResources, remoteUser, remotePwd, remoteIp, remotePort, remoteResourcesPath,
                resourcePathMap, remoteSystemConfigs, userId);

    }

    @Override
    @Async
    public void importCourseAndSendMessage(
            String remoteDBIp, String remoteDBPort, String remoteDBName, String remoteDBUser, String remoteDBPassword,
            String remoteIp, String remoteUser, String remotePassword, Integer remotePort, String remoteResourcesPath,
            List<Long> ids, Long userId) {

        Result result = Result.success();
        DateTime startTime = DateUtil.date();
        try {
            LOGGER.info("导课start");
            importCourse(remoteDBIp, remoteDBPort, remoteDBName, remoteDBUser, remoteDBPassword,
                    remoteIp, remoteUser, remotePassword, remotePort, remoteResourcesPath, ids, userId);
            LOGGER.info("导入课程成功" + DateUtil.betweenMs(startTime, DateUtil.date()) + "毫秒");
        } catch (Exception e) {
            LOGGER.error("导入课程失败", e);
            result = Result.error(e.getMessage());
        }

        CourseImportWebsocket.sendMessage(userId, result);

    }

    @Override
    public void cleanDB() {

        // 获取原先原值的模板表 及模板的资源信息
        List<TemplateDetailDTO> templateInfos = templateService.getTemplateInfo(null, null, null);

        // 清库
        configService.cleanDB();

        // 往数据库增加 模板表 及 资源表
        if (CollectionUtils.isNotEmpty(templateInfos)) {
            templateInfos.forEach(templateDetailDTO -> {
                Long resourceId = templateService.insertResource(
                        templateDetailDTO.getFileName(), templateDetailDTO.getName(),
                        templateDetailDTO.getRemark(), templateDetailDTO.getResourceType());
                templateService.insertTemplate(null, templateDetailDTO.getType(), resourceId);
            });
        }

        LOGGER.info("数据库清库处理完毕，正在清理静态资源");

        // 删除静态资源
        CmdUtil.exec("rm -rf " +
                MessageFormatter.format(LocalResourcesEnum.COURSE.getLocalUploadPath(), "*").getMessage());
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.MARKDOWN_PICTURE.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.PAPER.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.REPORT.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.NOTES.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.PDF.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.COURSE_TMP.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + LocalResourcesEnum.PRACTICE.getLocalUploadPath("*"));
        CmdUtil.exec("rm -rf " + path + File.separator + "media" + File.separator + "*");

        // 删除模板的静态资源
        String courseTemplatePath = LocalResourcesEnum.COURSE_TEMPLATE.getLocalUploadPath();
        String testTemplatePath = LocalResourcesEnum.TEST_TEMPLATE.getLocalUploadPath();
        List<String> courseFiles = null;
        List<String> testFiles = null;
        try {
            courseFiles = FileUtil.listFileNames(courseTemplatePath);
        } catch (IORuntimeException e) {

        }
        try {
            testFiles = FileUtil.listFileNames(testTemplatePath);
        } catch (IORuntimeException e) {

        }
        if (CollectionUtils.isNotEmpty(courseFiles)) {
            // 评语模版、课程实验报告模版
            List<String> fileNames = templateInfos.stream()
                    .filter(templateDetailDTO ->
                            Objects.equals(TemplateTypeEnum.COURSE_REPORT.getCode(), templateDetailDTO.getType())
                                    || Objects.equals(TemplateTypeEnum.EVALUATION.getCode(),
                                    templateDetailDTO.getType()))
                    .map(TemplateDetailDTO::getFileName)
                    .collect(Collectors.toList());

            courseFiles.forEach(s -> {
                if (!fileNames.contains(s)) {
                    FileUtil.del(courseTemplatePath + File.separator + s);
                }
            });

        }
        if (CollectionUtils.isNotEmpty(testFiles)) {

            List<String> fileNames = templateInfos.stream()
                    .filter(templateDetailDTO ->
                            Objects.equals(TemplateTypeEnum.TEST_REPORT.getCode(), templateDetailDTO.getType()))
                    .map(TemplateDetailDTO::getFileName)
                    .collect(Collectors.toList());

            testFiles.forEach(s -> {
                if (!fileNames.contains(s)) {
                    FileUtil.del(testTemplatePath + File.separator + s);
                }
            });

        }

        // 删除training非预置的数据
        List<String> trainingFiles = Lists.newArrayList();
        try {
            trainingFiles = FileUtil.listFileNames(LocalResourcesEnum.TRAINING.getLocalUploadPath());
        } catch (IORuntimeException e) {

        }
        List<String> deleteFiles = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(trainingFiles)) {
            List<Training> trainings = trainingMapper.selectByExample(new TrainingExample());
            if (CollectionUtils.isEmpty(trainings)) {
                deleteFiles.addAll(trainingFiles);
            } else {
                List<Long> ids = trainings.stream().map(Training::getId).collect(Collectors.toList());
                trainingFiles.forEach(s -> {
                    String idStr = StrUtil.subBefore(s, ".", true);
                    try {
                        Long id = Long.valueOf(idStr);
                        if (!ids.contains(id)) {
                            deleteFiles.add(s);
                        }
                    } catch (NumberFormatException e) {
                        deleteFiles.add(s);
                    }
                });
            }
        }
        deleteFiles.forEach(s -> {
            FileUtil.del(LocalResourcesEnum.TRAINING.getLocalUploadPath(s));
        });


        LOGGER.info("静态资源清理完毕");

    }

    private Map<DatabaseOperationEnum, Object> importCourseResouce(
            Map<Long, Long> courseIdMap, JdbcTemplate jdbcTemplate) {

        Map<DatabaseOperationEnum, Object> resultMap = Maps.newHashMap();

        ResourceRelationTypeEnum typeEnum = ResourceRelationTypeEnum.COURSE;

        // 批量删除当前服务器课程资源，若被其他教师占用，则只删除关联关系，不删除静态资源
        List<String> courseResource = courseService.deleteCourseResource(
                Lists.newArrayList(courseIdMap.values()), Lists.newArrayList(ResourcesTypeEnum.COURSE_OUTLINE),
                typeEnum, false);
        if (CollectionUtils.isNotEmpty(courseResource)) {
            resultMap.put(DatabaseOperationEnum.DELETE, courseResource);
        }

        // 获取远程服务器课程资源
        List<ResourceRelationDTO> remoteResources = queryRemoteCourseResource(
                jdbcTemplate, new String[]{
                        StringUtils.join(courseIdMap.keySet(), ","),
                        String.valueOf(ResourcesTypeEnum.COURSE_OUTLINE.getCode()),
                        String.valueOf(ResourceRelationTypeEnum.COURSE.getCode())});

        if (CollectionUtils.isEmpty(remoteResources)) return resultMap;

        // 转换并添加到当前数据库
        Long courseId = Lists.newArrayList(courseIdMap.values()).get(0);
        List<Resource> resources = convertResource(courseId, remoteResources);
        resourceService.insertBatch(resources);
        resourceService.insertBatchResourceRelation(
                convertResourceRelation(resources.stream().map(Resource::getId).collect(Collectors.toList()),
                        courseId, typeEnum));

        Map<String, String> map = Maps.newHashMap();
        for (int i = 0; i < remoteResources.size(); i++) {
            String remotePath = MessageFormatter.arrayFormat(
                    remoteCourseFile,
                    new String[]{remoteResources.get(i).getRemark(), remoteResources.get(i).getFileName()}
            ).getMessage();
            String localPath = LocalResourcesEnum.COURSE.getLocalUploadPath(
                    new String[]{resources.get(i).getRemark()}, resources.get(i).getFileName());
            map.put(remotePath, localPath);
        }

        resultMap.put(DatabaseOperationEnum.INSERT, map);

        return resultMap;

    }

    private List<Resource> convertResource(Long courseId, List<ResourceRelationDTO> remoteResources) {
        List<Resource> resources = Lists.newArrayList();
        String name = RandomUtil.simpleUUID();
        remoteResources.forEach(resourceRelationDTO -> {
            Resource resource = new Resource();
            resource.setName(resourceRelationDTO.getName());
            // 重命名
            resource.setFileName(
                    name + "." +
                            StrUtil.subAfter(resourceRelationDTO.getFileName(), ".", true));
            resource.setType(resourceRelationDTO.getType());
            resource.setRemark(String.valueOf(courseId));
            resources.add(resource);
        });
        return resources;
    }

    private List<ResourceRelation> convertResourceRelation(
            List<Long> resourceIds, Long courseId, ResourceRelationTypeEnum typeEnum) {
        List<ResourceRelation> result = Lists.newArrayList();
        resourceIds.forEach(resourceId -> {
            ResourceRelation resourceRelation = new ResourceRelation();
            resourceRelation.setResourceId(resourceId);
            resourceRelation.setObjId(courseId);
            resourceRelation.setType(typeEnum.getCode());
            result.add(resourceRelation);
        });
        return result;
    }

    private Map<Integer, Integer> importIcon(List<SystemConfig> remoteSystemConfigs, List<SystemConfig> configs) {

        Map<Integer, Integer> map = Maps.newHashMap();

        // 获取当前服务器的图标数据
        for (SystemConfig remoteSystemConfig : remoteSystemConfigs) {

            // 若数据库中有 就不插入，返回本地的id，若没有 就插入
            List<SystemConfig> data = configs.stream()
                    .filter(systemConfig ->
                            Objects.equals(systemConfig.getKeyWord(), remoteSystemConfig.getKeyWord())
                                    && Objects.equals(systemConfig.getKeyValue(), remoteSystemConfig.getKeyValue()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                map.put(remoteSystemConfig.getId(), data.get(0).getId());
                continue;
            }

            // 插入数据库
            SystemConfig systemConfig = new SystemConfig();
            systemConfig.setKeyWord(remoteSystemConfig.getKeyWord());
            systemConfig.setKeyValue(remoteSystemConfig.getKeyValue());
            systemConfig.setRemark(remoteSystemConfig.getRemark());
            configService.insertSystemConfig(systemConfig);
            map.put(remoteSystemConfig.getId(), systemConfig.getId());

        }

        return map;

    }

    private void convertCourseSort(List<CourseSort> courseSorts, Map<Long, Long> courseIdMap) {
        courseSorts.forEach(courseSort -> {
            courseSort.setCourseId(courseIdMap.get(courseSort.getCourseId()));
        });
    }

    private void convertChapterCourseSort(
            List<ChapterCourseSort> chapterCourseSorts, Map<Long, Long> chapterMap, Map<Long, Long> courseSortIdMap) {
        for (ChapterCourseSort chapterCourseSort : chapterCourseSorts) {
            chapterCourseSort.setChapterId(chapterMap.get(chapterCourseSort.getChapterId()));
            chapterCourseSort.setCourseSortId(courseSortIdMap.get(chapterCourseSort.getCourseSortId()));
        }
    }

    private void importCourseSort(Map<Long, Long> courseIdMap, Map<Long, Long> chapterMap, JdbcTemplate jdbcTemplate) {

        // 删除课程分类 及 章节与课程分类的关联关系
        chapterService.deleteChapterCourseSort(null, Lists.newArrayList(chapterMap.values()));
        courseService.deleteCourseSort(null, Lists.newArrayList(courseIdMap.values()));

        // 获取远程服务器的课程分类
        List<CourseSort> remoteCourseSorts = queryRemoteCourseSort(
                jdbcTemplate, StringUtils.join(courseIdMap.keySet(), ","));
        List<Long> remoteCourseSortIds = remoteCourseSorts.stream().map(CourseSort::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(remoteCourseSorts)) return;

        // 转换插入course_sort表
        convertCourseSort(remoteCourseSorts, courseIdMap);
        Map<Long, Long> courseSortIdMap = Maps.newHashMap();
        courseService.insertBatchCourseSort(remoteCourseSorts);
        for (int i = 0; i < remoteCourseSorts.size(); i++) {
            courseSortIdMap.put(remoteCourseSortIds.get(i), remoteCourseSorts.get(i).getId());
        }

        // 获取远程服务器的章节课程分类关联关系
        List<ChapterCourseSort> remoteChapterCourseSort = queryRemoteChapterCourseSort(
                jdbcTemplate, StringUtils.join(remoteCourseSortIds, ","));
        if (CollectionUtils.isEmpty(remoteChapterCourseSort)) return;

        // 转换并插入chapter_course_sort表
        convertChapterCourseSort(remoteChapterCourseSort, chapterMap, courseSortIdMap);
        chapterService.insertBatchChapterCourseSort(remoteChapterCourseSort);

    }

    private Map<DatabaseOperationEnum, Object> importCourseResource(
            Long courseId, Long remoteResourceId, Long resourceId, JdbcTemplate jdbcTemplate) {

        Map<DatabaseOperationEnum, Object> result = Maps.newHashMap();

        // 获取课程的信息
        List<CourseBasicDTO> course = courseService.listCourse(Lists.newArrayList(courseId), null, null, null);
        if (CollectionUtils.isEmpty(course)) return null;

        // 现在服务器的资源
        Resource resource = null;
        if (resourceId != null) {
            List<Resource> resources = resourceService.queryResource(Lists.newArrayList(resourceId));
            if (CollectionUtils.isNotEmpty(resources)) {
                resource = resources.get(0);
            }
        }

        // 远程服务器的资源
        Resource remoteResource = null;
        if (remoteResourceId != null) {
            List<Resource> remoteResources = queryRemoteResource(jdbcTemplate, String.valueOf(remoteResourceId));
            if (CollectionUtils.isNotEmpty(remoteResources)) {
                remoteResource = remoteResources.get(0);
            }
        }

        if (remoteResource == null && resource == null) return null;

        String remotePath = MessageFormatter.arrayFormat(
                remoteCourseFile,
                new String[]{
                        remoteResource == null ? "" : remoteResource.getRemark(),
                        remoteResource == null ? "" : remoteResource.getFileName()}).getMessage();

        // 添加资源 并且 修改课程基本信息
        if (remoteResource != null && resource == null) {

            // 插入资源
            resourceId = chapterService.insertResource(
                    remoteResource.getType(), remoteResource.getName(),
                    remoteResource.getFileName(), String.valueOf(courseId));

            // 修改course_basic表的resource_id
            CourseBasic courseBasic = new CourseBasic();
            courseBasic.setId(course.get(0).getCourseBasicId());
            courseBasic.setResourceId(resourceId);
            courseService.updateCourse(courseBasic);

            Map<String, String> localResourceMap = new HashMap<>();
            localResourceMap.put(remotePath, LocalResourcesEnum.COURSE.getLocalUploadPath(
                    new String[]{String.valueOf(courseId)}, remoteResource.getFileName()));
            result.put(DatabaseOperationEnum.UPDATE, localResourceMap);
            return result;

        }

        String localPath = LocalResourcesEnum.COURSE.getLocalUploadPath(
                new String[]{resource.getRemark()}, resource.getFileName());

        // 删除资源
        if (remoteResource == null && resource != null) {
            resourceService.deleteBatch(Lists.newArrayList(resourceId));
            result.put(DatabaseOperationEnum.DELETE, localPath);

            // 修改course_basic表的resource_id
            courseService.updateCourseBasicResource(course.get(0).getCourseBasicId(), null);

            return result;
        }

        // 修改资源，无需修改数据库
        Map<String, String> localResourceMap = new HashMap<>();
        localResourceMap.put(remotePath, localPath);
        result.put(DatabaseOperationEnum.UPDATE, localResourceMap);
        return result;
    }

    private Map<Long, Long> importRemoteCourse(
            CourseBasicDTO remoteCourse, CourseBasicDTO course, Map<Integer, Integer> iconMap, Long userId) {

        Map<Long, Long> courseMap = new HashMap<>();
        if (course != null) {
            courseMap.put(remoteCourse.getId(), course.getId());
            return courseMap;
        }

        // 新增课程
        CourseBasic courseBasic = BeanUtil.transform(CourseBasic.class, remoteCourse);
        courseBasic.setId(null);
        // 预置资源为空，是因为预置资源需要填写磁盘位置 位于课程下，课程id不存在，所以无法设置资源id
        courseBasic.setResourceId(null);
        courseBasic.setIcon(MapUtils.isEmpty(iconMap) ? null : iconMap.get(courseBasic.getIcon()));
        courseBasic.setPreseted(true);
        Course insertCourse = new Course();
        insertCourse.setUserId(userId);
        Long courseId = courseService.createCourse(courseBasic, insertCourse);
        courseMap.put(remoteCourse.getId(), courseId);
        return courseMap;

    }

    private Map<DatabaseOperationEnum, Object> importRemoteChapter(
            Long courseId, List<ChapterBasicInfoDTO> remoteSelectedChapters,
            List<ChapterBasicInfoDTO> allCourseChapters, Boolean selectedCourse, JdbcTemplate jdbcTemplate) {

        // 导入技术库
        Map<Long, Long> technologyMap = null;
        String technologyIdsStr = remoteSelectedChapters.stream()
                .filter(chapterTechnologyDTO -> StringUtils.isNotBlank(chapterTechnologyDTO.getTechnologyIds()))
                .map(ChapterBasicInfoDTO::getTechnologyIds).collect(Collectors.joining(","));
        if (StringUtils.isNotBlank(technologyIdsStr)) {
            List<Long> technologyIds = Arrays.stream(technologyIdsStr.split(","))
                    .map(Long::valueOf).collect(Collectors.toList());
            technologyMap = importTechnology(technologyIds, jdbcTemplate);
        }

        List<ChapterBasicInfoDTO> chapters = allCourseChapters.stream()
                .filter(chapterBasicInfoDTO -> Objects.equals(chapterBasicInfoDTO.getCourseId(), courseId))
                .collect(Collectors.toList());

        // 导入章节 先删除后增加
        return importChapterInfo(
                courseId, remoteSelectedChapters, chapters, technologyMap, selectedCourse, jdbcTemplate);

    }

    private Map<DatabaseOperationEnum, Object> importStep(Map<Long, Long> chapterMap, JdbcTemplate jdbcTemplate) {

        if (MapUtils.isEmpty(chapterMap)) return null;

        // 获取远程服务器的步骤
        List<StepChapter> stepChapters = queryRemoteStepChapter(jdbcTemplate,
                StringUtils.join(chapterMap.keySet(), ","));
        if (CollectionUtils.isEmpty(stepChapters)) return null;

        // 获取远程服务器的步骤资源
        List<Long> stepIds = stepChapters.stream().map(StepChapter::getStepId).collect(Collectors.toList());
        List<Step> steps = queryRemoteStep(jdbcTemplate, StringUtils.join(stepIds, ","));

        // 设置步骤map
        Map<Long, Long> stepMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(steps)) {
            List<Long> oldStepIds = steps.stream().map(Step::getId).collect(Collectors.toList());
            stepService.insertBatchStep(steps);
            for (int i = 0; i < steps.size(); i++) {
                stepMap.put(oldStepIds.get(i), steps.get(i).getId());
            }
        }

        // 转换章节步骤数据
        List<StepChapter> insertData = Lists.newArrayList();
        stepChapters.forEach(stepChapter -> {
            if (MapUtils.isNotEmpty(chapterMap) && chapterMap.containsKey(stepChapter.getChapterId())) {
                StepChapter obj = new StepChapter();
                obj.setId(stepChapter.getId());
                obj.setChapterId(chapterMap.get(stepChapter.getChapterId()));
                obj.setOrderNumber(stepChapter.getOrderNumber());
                if (MapUtils.isNotEmpty(stepMap) && stepMap.containsKey(stepChapter.getStepId())) {
                    obj.setStepId(stepMap.get(stepChapter.getStepId()));
                    insertData.add(obj);
                }
            }
        });

        // 设置步骤章节的map
        Map<Long, Long> stepChapterMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(insertData)) {
            List<Long> stepChapterIds = insertData.stream().map(StepChapter::getId).collect(Collectors.toList());
            stepService.insertBatchStepChapter(insertData);
            for (int i = 0; i < insertData.size(); i++) {
                stepChapterMap.put(stepChapterIds.get(i), insertData.get(i).getId());
            }
        }

        Map<DatabaseOperationEnum, Object> result = Maps.newHashMap();
        if (MapUtils.isNotEmpty(stepChapterMap)) {
            result.put(DatabaseOperationEnum.INSERT, stepChapterMap);
        }

        return result;
    }

    private Map<String, String> importResource(
            Long courseId, Map<Long, Long> map, ResourceRelationTypeEnum resourceRelationTypeEnum,
            List<String> deleteResources, JdbcTemplate jdbcTemplate) {

        if (MapUtils.isEmpty(map)) return null;

        Map<Long, StepChapter> stepChapterMap = Maps.newHashMap();
        if (resourceRelationTypeEnum == ResourceRelationTypeEnum.STEP && MapUtils.isNotEmpty(map)) {
            List<StepChapter> stepChapters = stepService.listStepChapterByIds(Lists.newArrayList(map.values()));
            stepChapterMap = BeanUtil.mapByKey("id", stepChapters);
        }

        // 获取远程章节的资源信息
        String message = MessageFormatter.arrayFormat(
                remoteResourceRelationConditionSQL,
                new String[]{
                        StringUtils.join(map.keySet(), ","),
                        String.valueOf(resourceRelationTypeEnum.getCode())}).getMessage();
        List<ResourceRelation> resourceRelations = queryRemoteResourceRelation(jdbcTemplate, message);
        if (CollectionUtils.isEmpty(resourceRelations)) return null;

        List<Resource> remoteResources = queryRemoteResource(jdbcTemplate,
                resourceRelations.stream()
                        .map(resourceRelation -> String.valueOf(resourceRelation.getResourceId()))
                        .collect(Collectors.joining(",")));
        if (CollectionUtils.isEmpty(remoteResources)) return null;

        String localPath = LocalResourcesEnum.CHAPTER.getLocalUploadPath(
                new String[]{String.valueOf(courseId)}, "");

        // 获取当前课程下的所有静态资源名称 将 需要删除的文件 进行过滤
        List<String> files = null;
        try {
            files = FileUtil.listFileNames(localPath);
        } catch (IORuntimeException e) {

        }
        if (CollectionUtils.isNotEmpty(deleteResources) && CollectionUtils.isNotEmpty(files)) {
            List<String> finalFiles = files;
            files = deleteResources.stream()
                    .filter(s -> s.contains(localPath)
                            && !finalFiles.contains(StrUtil.subAfter(s, "/", true)))
                    .map(s -> StrUtil.subAfter(s, "/", true))
                    .collect(Collectors.toList());
        }

        Map<String, String> resultMap = Maps.newHashMap();
        Map<Long, List<ResourceRelation>> resourceRelationMap = BeanUtil.aggByKeyToList(
                "resourceId", resourceRelations);
        for (Resource remoteResource : remoteResources) {

            String oldRemark = remoteResource.getRemark();

            // 设置课程id
            remoteResource.setRemark(String.valueOf(courseId));

            // 设置文件名称
            String name = remoteResource.getFileName();
            if (CollectionUtils.isNotEmpty(files) && files.contains(name)) {
                String fileName = StrUtil.subBefore(name, ".", true);
                String suffix = StrUtil.subAfter(name, ".", true);
                if (name.contains("ZDY-")) {
                    fileName = StrUtil.subBefore(name, "ZDY-", true);
                }

                if (resourceRelationTypeEnum == ResourceRelationTypeEnum.STEP
                        && MapUtils.isNotEmpty(map) && MapUtils.isNotEmpty(stepChapterMap)
                        && stepChapterMap.containsKey(
                        map.get(resourceRelationMap.get(remoteResource.getId()).get(0).getObjId()))) {
                    remoteResource.setFileName(
                            StringUtils.join(fileName, "ZDY-",
                                    String.format("%05d",
                                            stepChapterMap.get(map.get(resourceRelationMap.get(remoteResource.getId())
                                                    .get(0).getObjId()))
                                            .getChapterId()),
                                    "-", map.get(resourceRelationMap.get(remoteResource.getId()).get(0).getObjId()),
                                    ".", suffix));
                } else {
                    remoteResource.setFileName(
                            StringUtils.join(fileName, "ZDY-",
                                    String.format("%05d",
                                            map.get(resourceRelationMap.get(remoteResource.getId()).get(0).getObjId())),
                                    ".", suffix));
                }
            }

            // 将资源文件转换成map
            resultMap.put(
                    MessageFormatter.arrayFormat(remoteChapterFile, new String[]{oldRemark, name}).getMessage(),
                    LocalResourcesEnum.CHAPTER.getLocalUploadPath(
                            new String[]{String.valueOf(courseId)}, remoteResource.getFileName()));
        }

        // 插入数据库
        Map<Long, Long> resourceMap = Maps.newHashMap();
        List<Long> remoteResourceIds = remoteResources.stream().map(Resource::getId).collect(Collectors.toList());
        resourceService.insertBatch(remoteResources);
        for (int i = 0; i < remoteResources.size(); i++) {
            resourceMap.put(remoteResourceIds.get(i), remoteResources.get(i).getId());
        }

        // 插入关联表
        List<ResourceRelation> data = Lists.newArrayList();
        for (ResourceRelation resourceRelation : resourceRelations) {
            resourceRelation.setObjId(map.get(resourceRelation.getObjId()));
            resourceRelation.setResourceId(resourceMap.get(resourceRelation.getResourceId()));
            if (resourceRelation.getResourceId() != null) {
                data.add(resourceRelation);
            }
        }
        if (CollectionUtils.isNotEmpty(data)) {
            resourceService.insertBatchResourceRelation(data);
        }

        return resultMap;

    }

    private Map<DatabaseOperationEnum, Object> importChapterInfo(
            Long courseId, List<ChapterBasicInfoDTO> remoteChapterAndTask,
            List<ChapterBasicInfoDTO> chapterAndTask, Map<Long, Long> technologyMap, Boolean selectedCourse,
            JdbcTemplate jdbcTemplate) {

        Map<DatabaseOperationEnum, Object> result = Maps.newHashMap();

        // 先获取远程服务器章节及章节基本信息
        List<ChapterBasic> remoteChapterBasic = queryRemoteChapterBasic(jdbcTemplate,
                remoteChapterAndTask.stream()
                        .map(chapterBasicInfoDTO -> String.valueOf(chapterBasicInfoDTO.getChapterBasicId()))
                        .collect(Collectors.joining(",")));
        List<Chapter> remoteChapterInfo = queryRemoteChapterInfo(jdbcTemplate,
                remoteChapterAndTask.stream()
                        .map(chapterBasicInfoDTO -> String.valueOf(chapterBasicInfoDTO.getId()))
                        .collect(Collectors.joining(",")));

        // 将远程服务器章节及任务 和 现在服务器章节及任务 的任务进行过滤，只保留章节
        List<ChapterBasicInfoDTO> remoteChapters = ChapterEnum.CHAPTER.getConvertData(remoteChapterAndTask);
        List<ChapterBasicInfoDTO> chapters = ChapterEnum.CHAPTER.getConvertData(chapterAndTask);

        // 比对两个服务器的章节，获取已存在的远程章节
        List<String> remoteNames = remoteChapters.stream()
                .map(ChapterBasicInfoDTO::getName).collect(Collectors.toList());
        List<ChapterBasicInfoDTO> chapterExistData = chapters.stream()
                .filter(chapterBasicInfoDTO -> remoteNames.contains(chapterBasicInfoDTO.getName()))
                .collect(Collectors.toList());

        // 获取需要删除章节的id集合 以及 相同章节的序号
        Map<Long, Integer> orderMap = Maps.newHashMap();
        List<Long> deleteChapterIds = chapters.stream()
                .map(ChapterBasicInfoDTO::getId).collect(Collectors.toList());
        if (!selectedCourse) {
            deleteChapterIds = chapterExistData.stream()
                    .map(ChapterBasicInfoDTO::getId).collect(Collectors.toList());
            for (ChapterBasicInfoDTO chapterExistInfo : chapterExistData) {
                List<ChapterBasicInfoDTO> remoteData = remoteChapters.stream()
                        .filter(chapterBasicInfoDTO ->
                                Objects.equals(chapterBasicInfoDTO.getName(), chapterExistInfo.getName()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(remoteData)) {
                    orderMap.put(remoteData.get(0).getId(), chapterExistInfo.getOrderNumber());
                }
            }
        }

        // 删除章节、资源、题库、虚拟机等信息
        if (CollectionUtils.isNotEmpty(deleteChapterIds)) {
            List<String> deleteResourceInfos = chapterService.deleteChapter(
                    Lists.newArrayList(courseId), deleteChapterIds,
                    false, false, null);
            if (CollectionUtils.isNotEmpty(deleteResourceInfos)) {
                result.put(DatabaseOperationEnum.DELETE, deleteResourceInfos);
            }
        }

        // 添加数据库
        Integer chapterCount = selectedCourse ? null : chapters.size();

        // 插入到数据库
        if (CollectionUtils.isNotEmpty(remoteChapterBasic) && CollectionUtils.isNotEmpty(remoteChapterInfo)) {
            Map<Long, Long> insertMap = insertChatperAndChapterBasic(
                    courseId, remoteChapterBasic, remoteChapterInfo, technologyMap, chapterCount, orderMap);
            result.put(DatabaseOperationEnum.INSERT, insertMap);
        }

        return result;
    }

    private Map<Long, Long> insertChatperAndChapterBasic(
            Long courseId, List<ChapterBasic> insertChapterBasics, List<Chapter> insertChapters,
            Map<Long, Long> technologyMap, Integer chapterCount, Map<Long, Integer> orderMap) {

        // 转换技术库 并获取远程服务器的基本id集合
        convertChapterTechnology(insertChapterBasics, technologyMap);
        List<Long> remoteBasics = insertChapterBasics.stream().map(ChapterBasic::getId).collect(Collectors.toList());

        // 插入到数据库 chapterBasic表 并转换为Map<原来的章节基础id , 插入后的章节基础id>
        Map<Long, Long> basicMap = Maps.newHashMap();
        chapterService.insertBatchChapterBasic(insertChapterBasics);
        for (int i = 0; i < insertChapterBasics.size(); i++) {
            basicMap.put(remoteBasics.get(i), insertChapterBasics.get(i).getId());
        }

        // 将章节及任务进行转换
        for (Chapter insertChapter : insertChapters) {
            insertChapter.setCourseId(courseId);
            insertChapter.setChapterBasicId(basicMap.get(insertChapter.getChapterBasicId()));

            if (insertChapter.getParentId() != null && insertChapter.getParentId() > 0) continue;

            if (MapUtils.isNotEmpty(orderMap) && orderMap.get(insertChapter.getId()) != null) {
                insertChapter.setOrderNumber(orderMap.get(insertChapter.getId()));
            } else if (chapterCount != null) {
                chapterCount++;
                insertChapter.setOrderNumber(chapterCount);
            }
        }

        // 插入章节表
        Map<Long, Long> chapterMap = Maps.newHashMap();
        List<Chapter> chapters = insertChapters.stream()
                .filter(chapter -> chapter.getParentId() == null || chapter.getParentId() == 0)
                .collect(Collectors.toList());
        convertAndInsertChapter(chapterMap, chapters);

        // 获取任务信息
        List<Chapter> tasks = insertChapters.stream()
                .filter(chapter -> chapter.getParentId() != null && chapter.getParentId() > 0)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(tasks)) return chapterMap;

        // 转换 并 插入数据库并将章节Map进行存放
        for (Chapter task : tasks) {
            task.setParentId(chapterMap.get(task.getParentId()));
        }
        convertAndInsertChapter(chapterMap, tasks);
        return chapterMap;
    }

    private void convertAndInsertChapter(Map<Long, Long> chapterMap, List<Chapter> chapters) {
        List<Long> ids = chapters.stream().map(Chapter::getId).collect(Collectors.toList());
        chapterService.insertBatchChapter(chapters);
        for (int i = 0; i < chapters.size(); i++) {
            chapterMap.put(ids.get(i), chapters.get(i).getId());
        }
    }

    private void convertChapterTechnology(List<ChapterBasic> chapterBasics, Map<Long, Long> technologyMap) {

        for (ChapterBasic insertChapterBasic : chapterBasics) {
            if (StringUtils.isBlank(insertChapterBasic.getTechnologyIds())) continue;
            if (MapUtils.isEmpty(technologyMap)) {
                insertChapterBasic.setTechnologyIds(null);
                continue;
            }
            insertChapterBasic.setTechnologyIds(
                    Arrays.stream(insertChapterBasic.getTechnologyIds().split(","))
                            .map(s -> String.valueOf(technologyMap.get(Long.valueOf(s))))
                            .filter(s -> StringUtils.isNotBlank(s))
                            .collect(Collectors.joining(",")));
        }
    }

    private Map<Long, Long> importTechnology(List<Long> remoteTechnology, JdbcTemplate jdbcTemplate) {

        if (CollectionUtils.isEmpty(remoteTechnology)) return null;

        Map<Long, Long> result = Maps.newHashMap();

        // 获取远程服务器的部分技术库数据
        List<Technology> remoteTechnologies = queryRemoteTechnology(
                jdbcTemplate, StringUtils.join(remoteTechnology, ","));
        if (CollectionUtils.isEmpty(remoteTechnologies)) return null;

        // 获取现在服务器的所有技术库数据
        List<TechnologyDTO> technologies = technologyService.listTechnology();

        // 将远程服务器不存在的名称添加到数据库
        List<String> names = technologies.stream().map(TechnologyDTO::getName).collect(Collectors.toList());
        List<Technology> noExistData = remoteTechnologies.stream()
                .filter(technology -> !names.contains(technology.getName()))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(noExistData)) {
            technologyService.createTechnology(noExistData);
        }

        // 再获取一遍所有技能库
        List<TechnologyDTO> allTechnologyList = technologyService.listTechnology();

        // 将存在的名称 放到map中
        for (Technology remoteTechnologyData : remoteTechnologies) {
            List<TechnologyDTO> list = allTechnologyList.stream()
                    .filter(data -> Objects.equals(data.getName(), remoteTechnologyData.getName()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)) {
                result.put(remoteTechnologyData.getId(), list.get(0).getId());
            }
        }
        return result;
    }

    private List<ZtreeDTO> convertZtree(
            List<CourseBasicDTO> remoteCourses, List<ChapterBasicInfoDTO> remoteChapters) {

        // 获取目前数据库的课程
        List<CourseBasicDTO> courses = courseService.listCourse(
                null, true, true, CourseStatusEnum.SHARED.getCode());

        // 获取目前数据库的章节
        List<ChapterBasicInfoDTO> chapters = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(courses)) {
            chapters = chapterService.listChapterInfo(
                    courses.stream().map(CourseBasicDTO::getId).collect(Collectors.toList()), null, null);
        }

        // 转换
        List<ZtreeDTO> result = Lists.newArrayList();
        for (CourseBasicDTO remoteCours : remoteCourses) {

            // 获取远程服务器 某课程的章节
            List<ChapterBasicInfoDTO> remoteChapterList = remoteChapters.stream()
                    .filter(chapterBasicInfoDTO ->
                            Objects.equals(chapterBasicInfoDTO.getCourseId(), remoteCours.getId())
                                    && (chapterBasicInfoDTO.getParentId() == null
                                    || chapterBasicInfoDTO.getParentId() == 0)
                    ).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(remoteChapterList)) continue;

            // 获取当前服务器的 某课程的章节
            List<Long> courseIds = courses.stream()
                    .filter(courseBasicDTO -> Objects.equals(courseBasicDTO.getName(), remoteCours.getName()))
                    .map(CourseBasicDTO::getId)
                    .collect(Collectors.toList());
            List<ChapterBasicInfoDTO> chapterList = Lists.newArrayList();
            if (CollectionUtils.isNotEmpty(courseIds)) {
                chapterList = chapters.stream()
                        .filter(chapterBasicInfoDTO ->
                                Objects.equals(chapterBasicInfoDTO.getCourseId(), courseIds.get(0))
                                        && (chapterBasicInfoDTO.getParentId() == null
                                        || chapterBasicInfoDTO.getParentId() == 0)
                        ).collect(Collectors.toList());
            }

            ZtreeDTO ztreeDTO = new ZtreeDTO();
            ztreeDTO.setName(remoteCours.getName());
            List<ZtreeDTO> ztreeDTOS = convertChildZtree(remoteChapterList, chapterList);
            ztreeDTO.setChildren(ztreeDTOS);
            ztreeDTO.setExisted(CollectionUtils.isNotEmpty(courseIds) ? true : false);
            result.add(ztreeDTO);
        }

        return result;
    }

    private List<ZtreeDTO> convertChildZtree(
            List<ChapterBasicInfoDTO> remoteChapterList, List<ChapterBasicInfoDTO> chapters) {
        List<ZtreeDTO> result = Lists.newArrayList();
        for (ChapterBasicInfoDTO chapterBasicInfoDTO : remoteChapterList) {
            ZtreeDTO ztreeDTO = new ZtreeDTO();
            ztreeDTO.setId(chapterBasicInfoDTO.getId());
            ztreeDTO.setName(chapterBasicInfoDTO.getName());
            ztreeDTO.setType(chapterBasicInfoDTO.getType());
            ztreeDTO.setExisted(chapters.stream()
                    .filter(data -> Objects.equals(data.getName(), chapterBasicInfoDTO.getName()))
                    .count() > 0 ? true : false);
            result.add(ztreeDTO);
        }
        return result;
    }

    private void importStaticResource(
            List<String> deleteResources, String remoteUser, String remotePwd, String remoteIp, Integer remotePort,
            String remoteResourcesPath, Map<String, List<String>> resourcePathMap,
            List<SystemConfig> remoteSystemConfigs, Long userId) {

        String dbInfo = "数据库导入完毕";

        // 删除资源
        sendMessageAndRecordLogger(String.format("%s，正在删除课程资源... 进度1/6", dbInfo), userId);
        if (CollectionUtils.isNotEmpty(deleteResources)) {
            Sets.newHashSet(deleteResources).forEach(path -> {
                FileUtil.del(path);
            });
        }

        String remotePath = "";
        String localPath = "";
        try (SshUtil sshUtil = SshUtil.newInstance(remoteUser, remotePwd, remoteIp, remotePort)) {

            // 导入资源
            sendMessageAndRecordLogger(String.format("%s，正在传输课程静态资源... 进度2/6", dbInfo), userId);
            if (MapUtils.isNotEmpty(resourcePathMap)) {
                for (Map.Entry<String, List<String>> entry : resourcePathMap.entrySet()) {
                    remotePath = remoteResourcesPath + entry.getKey();
                    List<String> values = entry.getValue();
                    if (CollectionUtils.isEmpty(values)) continue;

                    for (String value : values) {
                        if (!new File(value).getParentFile().exists()) {
                            FileUtil.mkdir(new File(value).getParent());
                        }
                        sshUtil.get(remotePath, value);
                    }
                }
            }

            // 导入外层media文件夹
            sendMessageAndRecordLogger(String.format("%s，正在传输外层media文件夹... 进度3/6", dbInfo), userId);
            remotePath = StringUtils.join(
                    Lists.newArrayList(new File(remoteResourcesPath).getParent(), "media", "*"),
                    File.separator);
            localPath = path + File.separator + "media";
            if (!new File(localPath).exists()) {
                FileUtil.mkdir(new File(localPath));
            }
            sshUtil.get(remotePath, localPath);

            // 导入markdown-picture文件夹
            sendMessageAndRecordLogger(String.format("%s，正在传输markdown-picture文件夹... 进度4/6", dbInfo), userId);
            String remoteMarkdownPath = remoteResourcesPath + File.separator + "markdown-picture";
            localPath = LocalResourcesEnum.MARKDOWN_PICTURE.getLocalUploadPath();
            if (!new File(localPath).exists()) {
                FileUtil.mkdir(new File(localPath));
            }
            Vector<ChannelSftp.LsEntry> vector = sshUtil.ls(remoteMarkdownPath);
            List<String> files = vector == null ? null : vector.stream()
                    .filter(x -> !x.getAttrs().isDir()).map(ChannelSftp.LsEntry::getFilename)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(files)) {
                for (String file : files) {
                    remotePath = remoteMarkdownPath + File.separator + file;
                    sshUtil.get(remotePath, localPath);
                }
            }

            // 导入markdown-picture文件夹的media
            sendMessageAndRecordLogger(
                    String.format("%s，正在传输markdown-picture/media文件夹... 进度5/6", dbInfo), userId);
            remotePath = StringUtils.join(
                    Lists.newArrayList(remoteResourcesPath, "markdown-picture", "media", "*"),
                    File.separator);
            localPath = localPath + File.separator + "media";
            if (!new File(localPath).exists()) {
                FileUtil.mkdir(new File(localPath));
            }
            sshUtil.get(remotePath, localPath);

            // 导入system-file文件夹
            sendMessageAndRecordLogger(String.format("%s，正在传输system-file文件夹... 进度6/6", dbInfo), userId);
            for (SystemConfig remoteSystemConfig : remoteSystemConfigs) {
                localPath = LocalResourcesEnum.SYSTEM_FILE.getLocalUploadPath(remoteSystemConfig.getKeyValue());
                remotePath = StringUtils.join(
                        Lists.newArrayList(
                                remoteResourcesPath, "system-file", remoteSystemConfig.getKeyValue()),
                        File.separator);
                if (!new File(localPath).getParentFile().exists()) {
                    FileUtil.mkdir(new File(localPath).getParent());
                }
                sshUtil.get(remotePath, localPath);
            }

        } catch (Exception e) {
            LOGGER.error("远程文件文件夹的图片下载到本地失败。 远程地址{} 现在地址{}：" + e.getMessage(),
                    remotePath, localPath, e);
            throw new GlobalException(ResultEnum.FILE_DOWNLOAD_ERROR);
        }

    }

    private boolean isSelectedCourse(
            List<ChapterBasicInfoDTO> remoteChapters, Long remoteCourseId,
            List<ChapterBasicInfoDTO> remoteSelectedCourseChapters) {

        // 获取远程服务器课程下的所有章节
        List<ChapterBasicInfoDTO> remoteCourseChapters = remoteChapters.stream()
                .filter(chapterBasicInfoDTO ->
                        Objects.equals(chapterBasicInfoDTO.getCourseId(), remoteCourseId))
                .collect(Collectors.toList());

        return CollectionUtils.isEqualCollection(
                remoteSelectedCourseChapters.stream()
                        .map(ChapterBasicInfoDTO::getId).collect(Collectors.toList()),
                remoteCourseChapters.stream()
                        .map(ChapterBasicInfoDTO::getId).collect(Collectors.toList()));
    }

    private List<ChapterBasicInfoDTO> checkAndGetRemoteChapterTask(List<Long> chapterIds, JdbcTemplate jdbcTemplate) {
        String chapterIdsStr = StringUtils.join(chapterIds, ",");
        List<ChapterBasicInfoDTO> selectedChaptersAndTask = queryRemoteChapters(jdbcTemplate,
                MessageFormatter.arrayFormat(remoteChapterConditionSQL,
                        new String[]{chapterIdsStr, chapterIdsStr}).getMessage());
        if (CollectionUtils.isEmpty(selectedChaptersAndTask)
                || CollectionUtils.isEmpty(ChapterEnum.CHAPTER.getConvertData(selectedChaptersAndTask))) {
            throw new NotFoundException("远程服务器暂未找到已选中的部分章节");
        }

        return selectedChaptersAndTask;
    }

    private List<CourseBasicDTO> checkAndGetRemoteCourse(List<Long> courseIds, JdbcTemplate jdbcTemplate) {

        List<CourseBasicDTO> remoteCourses = queryRemoteCourses(jdbcTemplate,
                MessageFormatter.format(remoteCourseConditionSQL, StringUtils.join(courseIds, ","))
                        .getMessage());
        if (CollectionUtils.isEmpty(remoteCourses) || !CollectionUtils.isEqualCollection(
                remoteCourses.stream().map(CourseBasicDTO::getId).collect(Collectors.toList()), courseIds)) {
            throw new NotFoundException("远程服务器暂未找到已选中的课程");
        }

        return remoteCourses;
    }

    private Map<Long, Long> importDirection(JdbcTemplate jdbcTemplate) {

        // 获取学校类型
        Map<Integer, Integer> configMap = importSystemConfig(jdbcTemplate);
        if (MapUtils.isEmpty(configMap)) return null;

        // 获取远程数据、当前服务器数据
        List<Direction> remoteData = queryRemoteDirection(jdbcTemplate);
        List<Direction> currentData = directionService.queryDirection(null);
        if (CollectionUtils.isEmpty(remoteData)) return null;

        // 获取插入数据库的数据 以及 相同数据的对应关系
        Map<Long, Long> result = Maps.newHashMap();
        List<Direction> insertData = Lists.newArrayList();
        for (Direction remoteDirection : remoteData) {

            Integer type = configMap.get(remoteDirection.getType());

            List<Direction> sameData = currentData.stream()
                    .filter(direction -> Objects.equals(direction.getName(), remoteDirection.getName())
                            && Objects.equals(direction.getType(), type))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(sameData)) {
                result.put(remoteDirection.getId(), sameData.get(0).getId());
                continue;
            }

            remoteDirection.setType(type);
            insertData.add(remoteDirection);
        }

        if (CollectionUtils.isEmpty(insertData)) return result;

        // 转换序号
        insertData = convertDirection(insertData, currentData);

        // 添加到数据库
        List<Long> ids = insertData.stream().map(Direction::getId).collect(Collectors.toList());
        directionService.insertBatchDirection(insertData);
        for (int i = 0; i < insertData.size(); i++) {
            result.put(ids.get(i), insertData.get(i).getId());
        }

        return result;
    }

    private List<Direction> convertDirection(List<Direction> insertData, List<Direction> currentData) {

        List<Direction> result = Lists.newArrayList();

        // 更改序号
        Map<Integer, List<Direction>> typeMap = BeanUtil.aggByKeyToList("type", insertData);
        Map<Integer, List<Direction>> currentMap = BeanUtil.aggByKeyToList("type", currentData);

        typeMap.forEach((type, directions) -> {
            int size = MapUtils.isNotEmpty(currentMap) && CollectionUtils.isNotEmpty(currentMap.get(type)) ?
                    currentMap.get(type).size() : 0;
            for (Direction direction : directions) {
                direction.setOrderNum(++size);
                result.add(direction);
            }
        });

        return result;
    }

    private Map<Integer, Integer> importSystemConfig(JdbcTemplate jdbcTemplate) {

        Map<Integer, Integer> result = Maps.newHashMap();

        String key = SystemConfigEnum.SCHOOL_TYPE.getKey();
        List<String> configKeys = Lists.newArrayList(key);

        // 获取当前服务器、远程服务器的配置信息
        List<SystemConfig> configs = configService.listConfigByKeys(configKeys);
        List<SystemConfig> remoteConfigs = queryRemoteSystemConfig(
                jdbcTemplate, configKeys.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")));

        // 获取需要插入的数据
        List<String> configNames = configs.stream().map(SystemConfig::getKeyValue).collect(Collectors.toList());
        List<SystemConfig> insertData = remoteConfigs.stream()
                .filter(systemConfig -> !configNames.contains(systemConfig.getKeyValue())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(insertData)) {
            insertData.forEach(systemConfig -> {
                SystemConfig config = new SystemConfig();
                config.setKeyWord(key);
                config.setKeyValue(systemConfig.getKeyValue());
                config.setRemark(systemConfig.getRemark());
                configService.insertSystemConfig(config);
                result.put(systemConfig.getId(), config.getId());
            });
        }

        // 获取已存在的数据
        List<SystemConfig> data = remoteConfigs.stream()
                .filter(systemConfig -> configNames.contains(systemConfig.getKeyValue())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(data)) return result;

        configs.forEach(config -> {
            List<Integer> configIds = remoteConfigs.stream()
                    .filter(systemConfig -> Objects.equals(systemConfig.getKeyValue(), config.getKeyValue()))
                    .map(SystemConfig::getId).collect(Collectors.toList());
            result.put(configIds.get(0), config.getId());
        });

        return result;

    }

    private void importCourseExtend(
            Map<Long, Long> directionMap, Map<Long, Long> courseMap, JdbcTemplate jdbcTemplate) {

        // 删除当前服务器课程的选择信息
        directionService.deleteCourseExtend(null, Lists.newArrayList(courseMap.values()));

        if (MapUtils.isEmpty(directionMap)) return;

        // 获取远程的课程专业方向
        List<CourseExtend> courseExtends = queryRemoteCourseExtend(
                jdbcTemplate, new String[]{StringUtils.join(courseMap.keySet(), ",")});
        if (CollectionUtils.isEmpty(courseExtends)) return;

        // 转换并插入数据库
        courseExtends.forEach(courseExtend -> {
            courseExtend.setCourseId(courseMap.get(courseExtend.getCourseId()));
            courseExtend.setDirectionId(directionMap.get(courseExtend.getDirectionId()));
        });
        directionService.insertBatchCourseExtend(courseExtends);

    }

    private void sendMessageAndRecordLogger(String message, Long userId) {
        message = String.format(message);
        LOGGER.info(message);
        CourseImportWebsocket.sendMessage(userId, new Result<>(ResultEnum.PROGRESS, message));
    }

    private void convertResource(Map<String, List<String>> resourcePathMap, Map<String, String> resourceMap) {
        resourceMap.forEach((key, value) -> {
            List<String> data = Lists.newArrayList(value);
            if (MapUtils.isNotEmpty(resourcePathMap) && CollectionUtils.isNotEmpty(resourcePathMap.get(key))) {
                data.addAll(resourcePathMap.get(key));
            }
            resourcePathMap.put(key, data);
        });
    }

    private List<CourseBasicDTO> queryRemoteCourses(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteCourseSQL, data).getMessage(),
                new BeanPropertyRowMapper(CourseBasicDTO.class)
        );
    }

    private List<ChapterBasicInfoDTO> queryRemoteChapters(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteChapterSQL, data).getMessage(),
                new BeanPropertyRowMapper(ChapterBasicInfoDTO.class));
    }

    private List<ResourceRelation> queryRemoteResourceRelation(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteResourceRelationSQL, data).getMessage(),
                new BeanPropertyRowMapper(ResourceRelation.class));
    }

    private List<Resource> queryRemoteResource(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteResourceSQL, data).getMessage(),
                new BeanPropertyRowMapper(Resource.class));
    }

    private List<Technology> queryRemoteTechnology(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteTechnologySQL, data).getMessage(),
                new BeanPropertyRowMapper(Technology.class));
    }

    private List<ChapterBasic> queryRemoteChapterBasic(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteChapterBasicSQL, data).getMessage(),
                new BeanPropertyRowMapper(ChapterBasic.class));
    }

    private List<Chapter> queryRemoteChapterInfo(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteChapterInfoSQL, data).getMessage(),
                new BeanPropertyRowMapper(Chapter.class));
    }

    private List<CourseSort> queryRemoteCourseSort(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteCourseSortSQL, data).getMessage(),
                new BeanPropertyRowMapper(CourseSort.class));
    }

    private List<ChapterCourseSort> queryRemoteChapterCourseSort(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteChapterCourseSortSQL, data).getMessage(),
                new BeanPropertyRowMapper(ChapterCourseSort.class));
    }

    private List<SystemConfig> queryRemoteSystemConfig(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteIconSQL, data).getMessage(),
                new BeanPropertyRowMapper(SystemConfig.class));
    }

    private List<ResourceRelationDTO> queryRemoteCourseResource(JdbcTemplate jdbcTemplate, String[] data) {
        return jdbcTemplate.query(MessageFormatter.arrayFormat(remoteCourseResourceSQL, data).getMessage(),
                new BeanPropertyRowMapper(ResourceRelationDTO.class));
    }

    private List<Direction> queryRemoteDirection(JdbcTemplate jdbcTemplate) {
        return jdbcTemplate.query(remoteDirectionSQL, new BeanPropertyRowMapper(Direction.class));
    }

    private List<CourseExtend> queryRemoteCourseExtend(JdbcTemplate jdbcTemplate, String[] data) {
        return jdbcTemplate.query(MessageFormatter.arrayFormat(remoteCourseExtendSQL, data).getMessage(),
                new BeanPropertyRowMapper(CourseExtend.class));
    }

    private List<Step> queryRemoteStep(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteStepSQL, data).getMessage(),
                new BeanPropertyRowMapper(Step.class));
    }

    private List<StepChapter> queryRemoteStepChapter(JdbcTemplate jdbcTemplate, String data) {
        return jdbcTemplate.query(MessageFormatter.format(remoteStepChapterSQL, data).getMessage(),
                new BeanPropertyRowMapper(StepChapter.class));
    }
}
